import fs from 'node:fs'
import path from 'node:path'
import fetch from 'node-fetch'
import FigurineConfig from '../models/config.js'
import { gotScraping } from 'got-scraping'

export class FigurineWorkshop extends plugin {
  constructor () {
    super({
      name: '手办工坊',
      dsc: '使用Gemini API将图片手办化',
      event: 'message',
      priority: -500000000,
      rule: [
        { reg: '^#(手办|手办化[1-6]?)(?:@(\\d+)|(\\d+))?$', fnc: 'makeFigurine' },
        { reg: '^#(Q版化)(?:@(\\d+)|(\\d+))?$', fnc: 'makeFigurine' },
        { reg: '^#(痛屋化?)(?:@(\\d+)|(\\d+))?$', fnc: 'makeFigurine' },
        { reg: '^#(痛车化)(?:@(\\d+)|(\\d+))?$', fnc: 'makeFigurine' },
        { reg: '^#(cos化)(?:@(\\d+)|(\\d+))?$', fnc: 'makeFigurine' },
        { reg: '^#(cos自拍)(?:@(\\d+)|(\\d+))?$', fnc: 'makeFigurine' },
        { reg: '^#(吃柠檬|酸🍋|我吃🍋|孤独的我)(?:@(\\d+)|(\\d+))?$', fnc: 'makeFigurine' },
        { reg: '^#(第三视角)(?:@(\\d+)|(\\d+))?$', fnc: 'makeFigurine' },
        { reg: '^#(鬼图)(?:@(\\d+)|(\\d+))?$', fnc: 'makeFigurine' },
        { reg: '^#(第一视角)(?:@(\\d+)|(\\d+))?$', fnc: 'makeFigurine' },
        { reg: '^#bnn\\s*([\\s\\S]+)$', fnc: 'custom' }
      ]
    })

    // 创建插件数据目录
    this.pluginPath = path.join(process.cwd(), 'plugins', 'GeminiImage-plugin')
    this.dataPath = path.join(this.pluginPath, 'data')
    if (!fs.existsSync(this.dataPath)) {
      fs.mkdirSync(this.dataPath, { recursive: true })
    }

    // 手办化工坊使用记录文件路径
    this.usageRecordPath = path.join(this.dataPath, 'usage_record.json')

    // 读取配置文件
    this.config = FigurineConfig.getConfig()
    this.currentKeyIndex = 0
  }

  /**
   * 获取用户使用记录
   */
  getUsageRecord() {
    try {
      if (!fs.existsSync(this.usageRecordPath)) {
        const initData = {
          users: {},
          updatedAt: new Date().toISOString()
        };
        fs.writeFileSync(this.usageRecordPath, JSON.stringify(initData, null, 2));
        return initData;
      }
      const data = fs.readFileSync(this.usageRecordPath, 'utf8');
      return JSON.parse(data);
    } catch (err) {
      logger.error('[手办工坊] 读取用户使用记录失败:', err.message);
      return { users: {}, updatedAt: new Date().toISOString() };
    }
  }

  /**
   * 保存用户使用记录
   */
  saveUsageRecord(record) {
    try {
      record.updatedAt = new Date().toISOString();
      fs.writeFileSync(this.usageRecordPath, JSON.stringify(record, null, 2));
    } catch (err) {
      logger.error('[手办工坊] 保存用户使用记录失败:', err.message);
    }
  }

  /**
   * 检查用户是否可使用 (非管理员每60秒只能使用一次)
   */
  checkUserLimit(e) {
    // 直接通过 e.isMaster 判断是否为管理员
    if (e.isMaster) {
      return { allow: true, msg: '' };
    }

    const record = this.getUsageRecord();
    const userData = record.users[e.user_id] || { lastUseTime: 0 };
    const now = Date.now();
    const timeDiff = now - userData.lastUseTime;

    // 限制间隔为60秒
    const interval = 60 * 1000;

    if (timeDiff < interval) {
      const remainTime = Math.ceil((interval - timeDiff) / 1000);
      return {
        allow: false,
        msg: `❌ 您的使用频率过高，请等待 ${remainTime} 秒后再试`
      };
    }

    record.users[e.user_id] = {
      lastUseTime: now,
      count: (userData.count || 0) + 1
    };
    this.saveUsageRecord(record);
    return { allow: true, msg: '' };
  }

  async takeSourceMsg(e, { img } = {}) {
    let source = "";
    if (e.getReply) {
      source = await e.getReply();
    } else if (e.source) {
      if (e.group?.getChatHistory) {
        source = (await e.group.getChatHistory(e.source.seq, 1)).pop();
      } else if (e.friend?.getChatHistory) {
        source = (await e.friend.getChatHistory(e.source.time, 1)).pop();
      }
    }
    if (!source) return false;
    if (img) {
      let imgArr = [];
      for (let i of source.message) {
        if (i.type == "image") {
          imgArr.push(i.url);
        }
      }
      return imgArr.length > 0 ? imgArr : false;
    }
    return source;
  }

  async getAvatarUrl(qq) {
    return `https://q1.qlogo.cn/g?b=qq&nk=${qq}&s=640`;
  }

  async makeFigurine(e) {
    // 检查用户使用限制
    const limitCheck = this.checkUserLimit(e);
    if (!limitCheck.allow) {
      await e.reply(limitCheck.msg, { quote: e.messageId });
      return;
    }

    const cmdMatch = e.msg.match(/^#(手办|手办化[1-6]?|Q版化|痛屋化2?|痛车化|cos化|cos自拍|吃柠檬|酸🍋|我吃🍋|孤独的我|第三视角|鬼图|第一视角)(?:@(\d+)|(\d+))?$/);
    if (!cmdMatch) return;

    let cmd = "手办化";
    if (e.msg.startsWith("#手办化5")) cmd = "手办化5";
    else if (e.msg.startsWith("#手办化4")) cmd = "手办化4";
    else if (e.msg.startsWith("#手办化3")) cmd = "手办化3";
    else if (e.msg.startsWith("#手办化2")) cmd = "手办化2";
    else if (e.msg.startsWith("#手办化1")) cmd = "手办化1";
    else if (e.msg.startsWith("#Q版化")) cmd = "Q版化";
    else if (e.msg.startsWith("#cos化")) cmd = "cos化";
    else if (e.msg.startsWith("#痛屋化")) cmd = "痛屋化";
    else if (e.msg.startsWith("#痛车化")) cmd = "痛车化";
    else if (e.msg.startsWith("#cos自拍")) cmd = "cos自拍";
    else if (e.msg.startsWith("#孤独的我")) cmd = "孤独的我";
    else if (e.msg.startsWith("#第三视角")) cmd = "第三视角";
    else if (e.msg.startsWith("#鬼图")) cmd = "鬼图";
    else if (e.msg.startsWith("#第一视角")) cmd = "第一视角";
    else if (e.msg.startsWith("#吃柠檬") || e.msg.startsWith("#酸") || e.msg.startsWith("#我吃")) cmd = "吃柠檬";

    const targetQQ = cmdMatch[2] || cmdMatch[3];

    // 定义cmd到promptKey的映射关系
    const cmdPromptMap = {
      '手办化': 'figurine',
      '手办化1': 'figurine',
      '手办化2': 'figurine2',
      '手办化3': 'figurine3',
      '手办化4': 'figurine4',
      '手办化5': 'figurine5',
      'Q版化': 'qversion',
      'cos化': 'cosplay',
      '痛屋化': 'otakuRoom',
      '痛车化': 'itasha',
      '吃柠檬': 'lemon',
      '孤独的我': 'lemon',
      '鬼图': 'ghost',
      '第三视角': 'view3',
      '第一视角': 'view1',
      'cos自拍': 'cosplaySelf'
    };

    // 获取对应的promptKey，如果没有匹配则默认为'figurine'
    const promptKey = cmdPromptMap[cmd] || 'figurine';

    let replyMsg = `正在生成${cmd}形象，请稍候...`;

    return this.processImage(e, promptKey, targetQQ, replyMsg);
  }

  async custom(e) {
    // 检查用户使用限制
    const limitCheck = this.checkUserLimit(e);
    if (!limitCheck.allow) {
      await e.reply(limitCheck.msg, { quote: e.messageId });
      return;
    }

    // 提取用户自定义提示词
    const match = e.msg.match(/^#bnn\s*([\s\S]+)$/);
    if (!match || !match[1].trim()) {
      await e.reply("❌ 命令格式错误，请使用：#bnn <你的自定义提示词> [图片/@用户]", { quote: e.messageId });
      return;
    }
    const userPrompt = match[1].trim();

    return this.processImage(e, null, null, "正在处理自定义提示词...", userPrompt);
  }

  async processImage(e, promptKey, targetQQ, replyMsg, customPrompt = null) {
    await e.reply(replyMsg, { quote: e.messageId },{ recallMsg: 30 });

    let imageUrls = [];

    // 只有当存在QQ号参数（且与命令之间有空格）时才获取对应头像
    if (targetQQ) {
      imageUrls.push(await this.getAvatarUrl(targetQQ));
    } else {
      // 从引用消息获取图片
      const sourceImg = await this.takeSourceMsg(e, { img: true });
      if (sourceImg && sourceImg.length > 0) {
        imageUrls = imageUrls.concat(sourceImg);
      }

      // 从当前消息获取图片
      if (imageUrls.length === 0) {
        const imgSegs = e.message.filter(m => m.type === "image");
        if (imgSegs.length > 0) {
          for (const imgSeg of imgSegs) {
            if (imgSeg.url) {
              imageUrls.push(imgSeg.url);
            }
          }
        }
      }

      // 从@用户获取头像
      if (imageUrls.length === 0) {
        const atSeg = e.message.find(m => m.type === "at");
        if (atSeg?.qq) {
          imageUrls.push(await this.getAvatarUrl(atSeg.qq));
        }
      }

      // 如果都没有，使用发送者头像
      if (imageUrls.length === 0) {
        imageUrls.push(await this.getAvatarUrl(e.user_id));
      }
    }

    try {
      const imageData = await this.generateFigurineWithGemini(imageUrls, promptKey, customPrompt);
      if (imageData) {
        await this.reply(segment.image(`base64://${imageData}`));

        // 保存图片
        if (this.config.save_image) {
          const timestamp = new Date().getTime();
          const filename = `gemini_${promptKey || 'custom'}_${timestamp}.png`;
          const savePath = path.join(this.dataPath, filename);
          const buffer = Buffer.from(imageData, 'base64');
          fs.writeFileSync(savePath, buffer);
          logger.info(`[手办工坊] 图片已保存至: ${savePath}`);
        }
      } else {
        await this.reply('生成失败，未获取到图片数据',false,{ recallMsg: 30 });
      }
    } catch (err) {
      logger.error(`[手办工坊] 生成失败: ${err}`);
      await this.reply(`生成失败: ${err.message}`,false,{ recallMsg: 30 });
    }
  }

  async generateFigurineWithGemini(imageUrls, promptKey, customPrompt) {
    // 获取图片数据
    const imageBuffers = [];
    for (const imageUrl of imageUrls) {
      const imageBuffer = await this.downloadImage(imageUrl);
      if (!imageBuffer) {
        throw new Error('图片下载失败');
      }
      imageBuffers.push(imageBuffer);
    }

    // 获取当前API密钥
    const apiKey = this.getCurrentApiKey();
    if (!apiKey) {
      throw new Error('未配置Gemini API密钥');
    }

    // 获取提示词
    let finalPrompt;
    if (customPrompt) {
      finalPrompt = customPrompt;
    } else {
      finalPrompt = this.config.prompts[promptKey];
      if (!finalPrompt) {
        throw new Error(`配置错误：未能在配置文件中找到名为 '${promptKey}' 的提示词`);
      }
    }

    //logger.info(`[手办工坊] Gemini 手办化 Prompt (${promptKey || 'custom'}): ${finalPrompt}`);

    const model = this.config.model;
    const apiBaseUrl = this.config.api_base_url || 'https://generativelanguage.googleapis.com';
    const url = `${apiBaseUrl}/v1beta/models/${model}:generateContent?key=${apiKey}`;

    // 构建parts数组，包含提示词和所有图片
    const parts = [{ text: finalPrompt }];
    for (const imageBuffer of imageBuffers) {
      const base64Image = imageBuffer.toString('base64');
      parts.push({
        inlineData: {
          mimeType: 'image/png',
          data: base64Image
        }
      });
    }

    const payload = {
      contents: [
        {
          role: 'user',
          parts: parts
        }
      ],
      generationConfig: {
        responseModalities: ['TEXT', 'IMAGE']
      }
    }

    const response = await this.withRetry(async (key) => {
      const res = await gotScraping({
        url: url,
        method: 'POST',
        headers: {
          'Content-Type': 'application/json'
        },
        body: JSON.stringify(payload)
      })

      if (res.statusCode !== 200) {
        const errorText = res.body
        throw new Error(`API请求失败: HTTP ${res.statusCode}, 响应: ${errorText}`)
      }

      const data = JSON.parse(res.body)
      return data
    })

    if (!response) {
      throw new Error('所有API密钥均尝试失败')
    }

    if (response.candidates &&
      response.candidates.length > 0 &&
      response.candidates[0].content &&
      response.candidates[0].content.parts) {

      for (const part of response.candidates[0].content.parts) {
        if (part.inlineData && part.inlineData.data) {
          return part.inlineData.data
        }
      }
    }

    throw new Error('操作成功，但未在响应中获取到图片数据')
  }

  getCurrentApiKey() {
    if (!this.config.gemini_api_keys || this.config.gemini_api_keys.length === 0) {
      return null
    }
    return this.config.gemini_api_keys[this.currentKeyIndex]
  }

  switchKey() {
    if (!this.config.gemini_api_keys || this.config.gemini_api_keys.length === 0) {
      return
    }
    this.currentKeyIndex = (this.currentKeyIndex + 1) % this.config.gemini_api_keys.length
    logger.info(`[手办工坊] 切换到下一个 Gemini API 密钥（索引：${this.currentKeyIndex}）`)
  }

  async withRetry(operation) {
    const maxAttempts = this.config.gemini_api_keys?.length || 0
    if (maxAttempts === 0) {
      return null
    }

    for (let attempt = 0; attempt < maxAttempts; attempt++) {
      const currentKey = this.getCurrentApiKey()
      logger.info(`[手办工坊] 尝试操作（密钥索引：${this.currentKeyIndex}，次数：${attempt + 1}/${maxAttempts}）`)

      try {
        return await operation(currentKey)
      } catch (err) {
        logger.error(`[手办工坊] 第${attempt + 1}次尝试失败：${err.message}`)
        if (attempt < maxAttempts - 1) {
          this.switchKey()
        } else {
          logger.error('[手办工坊] 所有API密钥均尝试失败')
        }
      }
    }

    return null
  }

  async downloadImage(url) {
    try {
      const response = await fetch(url)
      if (!response.ok) {
        throw new Error(`下载图片失败: HTTP ${response.status}`)
      }
      const buffer = await response.arrayBuffer()
      return Buffer.from(buffer)
    } catch (err) {
      logger.error(`[手办工坊] 图片下载失败: ${err}`)
      return null
    }
  }
}
